package com.lagou.cl.server;

import com.lagou.cl.servlet.AbstractHttpServlet;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Bootstrap {

	/**
	 * 端口号
	 */
	private static int port = 8080;

	public static void main(String[] args) {

		try {
			start();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private static void start() throws IOException {


		//ServerSocket serverSocket = new ServerSocket(port);


		//1 接受请求(socket通信)，返回固定数据到页面
		/*while (true) {

			//监听8080端口。该方法将阻塞，直到建立连接为止
			Socket accept = serverSocket.accept();

			//获取输出流
			OutputStream outputStream = accept.getOutputStream();

			String data = "Hello Minicat";
			String response = HttpProtocolUtil.get_200(data.getBytes(StandardCharsets.UTF_8).length) + data;

			outputStream.write(response.getBytes(StandardCharsets.UTF_8));

			outputStream.close();
			accept.close();
		}*/

		//2 封装request和response，返回html静态资源文件
		/*while (true) {

			//监听8080端口。该方法将阻塞，直到建立连接为止
			Socket accept = serverSocket.accept();

			//获取输入数据
			Request request = new Request(accept.getInputStream());

			Response response = new Response(accept.getOutputStream());

			response.outHtml(request.getUrl());
			accept.close();
		}*/

		//3 请求动态资源
		/*loadServlet();
		while (true) {

			//监听8080端口。该方法将阻塞，直到建立连接为止
			Socket accept = serverSocket.accept();

			//获取输入数据
			Request request = new Request(accept.getInputStream());

			Response response = new Response(accept.getOutputStream());

			AbstractHttpServlet httpServlet = servletMap.get(request.getUrl());
			if (httpServlet == null) {
				response.outHtml(request.getUrl());
			} else {
				httpServlet.service(request, response);
			}

			response.outHtml(request.getUrl());
			accept.close();
		}*/

		//4 多线程（不使用线程池）
		/*loadServlet();
		while (true) {

			//监听8080端口。该方法将阻塞，直到建立连接为止
			Socket accept = serverSocket.accept();

			RequestProcessor processor = new RequestProcessor(accept, servletMap);
			processor.start();
		}*/

		//5 多线程（使用线程池）
		/*loadServlet();
		while (true) {

			//监听8080端口。该方法将阻塞，直到建立连接为止
			Socket accept = serverSocket.accept();
			RequestProcessor processor = new RequestProcessor(accept, servletMap);
			TheadPoolUtil.getThreadPoolExecutor().execute(processor);
		}*/

		//6 模拟webapps目录
		Catalina catalina = initCatalina();
		catalina.load();
		catalina.start();

	}

	private static Catalina initCatalina() {

		Catalina newInstance = null;

		try {
			String name = Bootstrap.class.getPackage().getName();
			newInstance = (Catalina) Class.forName(name + ".Catalina").newInstance();
		} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
			e.printStackTrace();
		}
		return newInstance;

	}


	private static Map<String, AbstractHttpServlet> servletMap = new HashMap<>();

	/**
	 * 加载解析web.xml,初始化servlet
	 */
	private static void loadServlet() {


		//读取web.xml并解析
		InputStream resourceAsStream = Bootstrap.class.getClassLoader().getResourceAsStream("web.xml");
		try {
			Document document = new SAXReader().read(resourceAsStream);

			Element webApp = document.getRootElement();
			List<Element> servlets = webApp.selectNodes("//servlet");
			for (Element servlet : servlets) {
				Element servletNameElement = (Element) servlet.selectSingleNode("servlet-name");
				Element servletClassElement = (Element) servlet.selectSingleNode("servlet-class");

				String servletName = servletNameElement.getStringValue();
				String servletClass = servletClassElement.getStringValue();

				Element servletMapping = (Element) webApp.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
				Element urlPatternElement = (Element) servletMapping.selectSingleNode("url-pattern");
				String urlPattern = urlPatternElement.getStringValue();

				//实例化
				servletMap.put(urlPattern, (AbstractHttpServlet) Class.forName(servletClass).newInstance());
			}

		} catch (DocumentException | IllegalAccessException | InstantiationException | ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
}
